home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Macintosh Common Lisp Related / User Contributions / Misc.sea / Misc / print-u.lisp < prev    next >
Encoding:
Text File  |  1993-02-26  |  63.3 KB  |  1,577 lines  |  [TEXT/CCL2]

  1. (in-package :ccl)
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;; print-u.lisp
  4. ;;
  5. ;; Copyright  1992 University of Toronto, Department of Computer Science
  6. ;; All Rights Reserved
  7. ;;
  8. ;; author: Mark A. Tapia markt@dgp.toronto.edu or markt@dgp.utoronto.ca
  9. ;;
  10. ;; print-u is a package for printing windows and documents. 
  11. ;; The following methods and functions are exported:
  12. ;;        get-printer-error    for returning the error condition or nil (no error)
  13. ;;        page-size            point indicating the page size used for printing
  14. ;;        picture-hardcopy     for quickdraw pictures
  15. ;;        print-contents       for drawing the nested views of a window
  16. ;;        view-print-contents  for printing a series of views
  17. ;;
  18. ;; Internal (unexported) routines of interest
  19. ;;        document-hardcopy    for printing a general document
  20. ;;        window-hardcopy      for printing the contents of a window using
  21. ;;                             print-contents
  22.  
  23. ;;                             Routines that handle public and private print records
  24. ;;        check-print-prec     retrieves and validates the print record (get-print-prec object)
  25. ;;        default-prec         creates a default private print record
  26. ;;        get-prec             retrieves (and possibly creates) a print record for an object
  27. ;;        get-print-prec       calls get-prec on the outermost containing view
  28. ;;        prec-get             retrieves a print record for an object
  29. ;;        prec-put             associates a print-record with an object
  30. ;;        remove-prec          removes a print-record associated with an object
  31. ;;        remove-hc-prec       removes the public print-record
  32. ;;        replace-prec         replaces the print record associated with the object
  33. ;;                             only if it is different
  34. ;;        update-file-prec     saves a copy of a private print record in a resource 
  35. ;;        view-file-name       the pathname of the file associated with an object
  36. ;;
  37. ;; Acknowledgements:
  38. ;;     This code is based on print-utils.lisp written by DEH 6/20/91 and
  39. ;;     based on hardcopy.lisp with copyright 1988-89 Apple Computer, Inc. 
  40. ;;     The print-utils code has been modified to work in MCL2.0 and
  41. ;;     to print the contents of other views and to support generalized printing.
  42. ;;
  43. ;;     This code also uses the with-view-font and with-pen-state macros
  44. ;;     from oodles-of-utils:quickdraw-u.lisp by Michael S. Engber.
  45. ;;     Copyright  1991 Northwestern University Institute for the Learning Sciences
  46. ;;     All Rights Reserved.
  47. ;;
  48. ;;     Support for private print records was based on suggestions by Gregory
  49. ;;     Wilcox. The ideas were refined by Bill St. Clair.
  50. ;;
  51. ;; Update history:
  52. ;;  1992-06-07  Added page-size method for retrieving the page size
  53. ;;  1992-10-27  Support added for private print records stored with the
  54. ;;              file in the resource fork (:type :prec :resource-id 128).
  55. ;;
  56. ;; NOTE: Every window has a private print record which controls the
  57. ;;       way the window will be printed and the attributes in the
  58. ;;       print-style-dialog box. The private print record is stored in the
  59. ;;       resource fork of the file when it is saved (:type :prec :resource-d 128)
  60. ;;       and when the Page Setup method is selected.
  61. ;;       The private print record is restored when the file is edited again.
  62. ;;       
  63. ;;       Every specific view uses the private print record of the outermost
  64. ;;       view containing the specific view.
  65. ;;
  66. ;;       A private print record of a window is saved when the window
  67. ;;       is saved (using Save, Save As, or Save Copy As and when the
  68. ;;       window is closed and needs to be saved. Methods are defined
  69. ;;       for fred windows.
  70. ;;
  71. ;;       For all other windows, you must provide a method for saving
  72. ;;       the file (ccl::window-save using ccl::window-file-save which
  73. ;;       must return the pathname) and a method for (view-file-name window)
  74. ;;        
  75. ;;       When a titled fred-window is saved (using the file menu
  76. ;;       items "save", "Save As ..." "Save Copy As..."), the page 
  77. ;;       setup attributes are saved in a print record in the file. 
  78. ;;       The record is placed in the :prec resource with id 128.  
  79. ;;       When the file is reopened in a fred-window, the page setup 
  80. ;;       attributes are restored.
  81. ;;    
  82. ;;
  83. ;;       Every other object uses a shared, public print record *print-hc-prec*.
  84. ;;       This print record is initialized at the beginning of a session.
  85. ;;
  86. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  87. ;;
  88. ;; Warnings:
  89. ;;     1. If you are running MCL2.0b1p3 or earlier, you must remove
  90. ;;        the semi-colons from before the (pushnew ...) form below.
  91.  
  92. ;;(pushnew :not-mcl-final *features*)
  93.  
  94. ;;
  95. ;;     2. This code will only work if the records definitions in the
  96. ;;        library;interfaces:printTraps.lisp are correct. 
  97. ;;        See the note below.
  98. ;;
  99. ;;     3. The code has been tested with LaserWriters but has not
  100. ;;        been tested with ImageWriters, StyleWriters etc. The routines
  101. ;;        use standard quickdraw calls.
  102. ;;
  103. ;;     4. This code changes the File menu-items for Page Setup and Print.
  104. ;;        The Page Setup menu item is changed to a window-menu-item and
  105. ;;        the associated menu-item action is #'ccl::page-setup. 
  106. ;;        Changing the page setup for a window does not affect
  107. ;;        other windows.
  108. ;;        
  109. ;;     5. Printing can only be cancelled by pressing Command-period.
  110. ;;        Printing cannot be stopped while the current page is being
  111. ;;        printed. but will be stopped before printing the next page.
  112. ;;  
  113. ;;     6. Due to a bug in background printing, we cannot display the
  114. ;;        current page being printed under certain conditions.
  115. ;;        When the print monitor is displaying the status of printing
  116. ;;        (with background printing off), (event-dispatch) does not return.
  117. ;;        As a result, the print progress dialog box does not indicate the
  118. ;;        page number of the page being printed.
  119. ;;
  120. ;;     7. The internal code for printing a document runs without interrupts
  121. ;;        with the result that no other work can proceed until either
  122. ;;        the hardcopy routine returns (or aborts) or is cancelled by
  123. ;;        pressing command-period.
  124. ;;         
  125. ;;
  126. ;;  Six examples of using the package are included at the end of this file:
  127. ;;    four printing examples, for printing various objects:
  128. ;;    - a small window
  129. ;;    - a picture
  130. ;;    - a large window
  131. ;;    - a general document
  132. ;;    and two examples of using private print records
  133. ;;    - creating a file, changing its print record, saving it and restoring it.
  134. ;;    - developing a class of views that store a print record in a slot
  135. ;;
  136. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  137.  
  138. #|
  139. ;;---------------------------Note-------------------------------------
  140.  
  141. ****Warning****
  142. Before loading this file, evaluate
  143.     (record-length :TPrint)
  144. This should return 120.
  145.  
  146. If the record-length is not 120, the tprstl and tprxinfo records 
  147. in the file printTraps.lisp in interfaces folder in the library
  148. folder must be replaced by the following: 
  149.  
  150. (defrecord tprstl
  151.   (wdev :signed-integer)
  152.   (ipagev :signed-integer)
  153.   (ipageh :signed-integer)
  154.   (bport :signed-byte)
  155.   (feed :unsigned-byte))
  156.  
  157. (defrecord tprxinfo
  158.   (irowbytes :signed-integer)
  159.   (ibandv :signed-integer)
  160.   (ibandh :signed-integer)
  161.   (idevbytes :signed-integer)
  162.   (ibands :signed-integer)
  163.   (bpatscale :signed-byte)
  164.   (bulthick :signed-byte)
  165.   (buloffset :signed-byte)
  166.   (bulshadow :signed-byte)
  167.   (scan :unsigned-byte)
  168.   (bxinfox :signed-byte))
  169.  
  170. Perform the following steps to update the record definitions:
  171. 1. Replace the record definitions in the source file
  172.    library;interfaces:printTraps.lisp with the definitions above. 
  173. 2. Evaluate the following expression to rebuild the index files
  174.    (ccl::reindex-interfaces)
  175.    You will now be able to access the new record definitions.
  176. 3. Quit from MCL. To free up the cons space.
  177. 4. Startup MCL again.
  178.  
  179. ----------------------Exported routines------------------------
  180.  
  181. The following exported routines allow the user to change the 
  182. print style for windows. Changing a print style only affects the
  183. current session. The print styles are reset upon re-entering MCL
  184. and are not stored with the document. Changing the style for 
  185. a fred window only changes the style of all fred windows during
  186. the session. Similarly changing the style of a non-fred window 
  187. only changes the styles for all fred windows.
  188.  
  189. page-setup                              ; method
  190. Changes the print style for a window.
  191.  
  192. (page-setup fred-window)
  193. Same as selecting the file Page Setup menu item from the
  194. standard *file-menu*.
  195. Displays the page setup dialog box and allows the user to
  196. change the style attributes for printing the window
  197. but does not affect the style for printing other windows
  198. or documents.
  199.  
  200. (page-setup t)
  201. Displays the page setup dialog box and allows the user to
  202. change the style attributes for all items that do not have
  203. private print records.
  204.  
  205. page-size                              ; method
  206. Returns a point indicating the page size used for printing
  207. fred or non-fred windows. The page-size for a fred window 
  208. may be different from that of a non-fred window.
  209.  
  210. (page-setup fred-window)
  211. (page-setup t)
  212.  
  213. The following exported routines direct output to a printer or
  214. to a PostScript file.
  215.  
  216. picture-hardcopy                        ; function
  217. picture-hardcopy picture &optional show-dialog?
  218.   Directs the quickdraw picture to the printer
  219.     picture       a picture
  220.     show-dialog?  ignored
  221.  
  222.    If no printer errors occurred and the user did not cancel
  223.       returns nil
  224.    otherwise 
  225.       returns the non-zero print error code which caused the termination
  226.  
  227. print-contents                          ; method
  228. print-contents view &optional (offset #@(0 0))
  229. Executes the quickdraw commands for drawing the contents of a view.
  230.  
  231. When offset is #@(0 0), uses local coordinates for drawing,
  232. otherwise adjusts coordinates by subtracting offset from coordinates.
  233.  
  234. Print-contents supports the following types of views:
  235.     window                    - draws a box around the content area
  236.                                 of the window and prints the contents
  237.                                 of the subviews.
  238.  
  239.     static-text-dialog-item   - draws a box around the item
  240.                                 and prints the text with the view font
  241.  
  242.     editable-text-dialog-item - draws a box around the item
  243.                                 and prints the text with the view font
  244.  
  245.     button-dialog-item        - draws the button and the text within
  246.  
  247.     view                      - prints the contents of the subviews
  248.  
  249.     sv                        - does nothing
  250.  
  251. get-printer-error                       ; function
  252. (get-printer-error)
  253. either returns nil or a printer-condition
  254. If nil, indicates no errors occurred during the last print request.
  255. Otherwise, returns the printer-condition with slots:
  256. phase - either $err-printer??? or nil
  257. code  - either the code returned from the printer operation or nil
  258. cond  - either nil or an error condition when not a printer error
  259.  
  260. ----------------------Unexported routines------------------------
  261.  
  262. Window-hardcopy prints the contents of a window.
  263. Specialize if you want to acheive different effects for
  264. other kinds of windows.
  265.  
  266. Use view-print-contents to initiate the printing of a view
  267. and all of its subviews.
  268.  
  269. Use the print-contents methods as the basis for developing
  270. methods for other types of views.
  271.  
  272. Document-hardcopy is a general routine that forms the basis
  273. for other print routines. Call this routine if you want
  274. to develop your own custom printing functions fo documents
  275. and windows.
  276.  
  277. window-hardcopy                         ; method
  278. window-hardcopy (window window) &optional (show-dialog? t)
  279.    Prints the window, The show-dialog? parameter is present
  280.    for compatibility with the standard method for fred-windows
  281.    and is used to display the print job dialog.
  282.    
  283.    The basic routine calls print-contents on the window, which
  284.    repeatedly calls print-contents on the views and subviews.
  285.  
  286.    If no printer errors occurred and the user did not cancel
  287.       returns t
  288.    otherwise 
  289.       returns nil indicating an error occurred in printing
  290.  
  291.     Parameters
  292.       window           the window to be printed
  293.        show-dialog?    display the print job dialog (default t)
  294.  
  295.  
  296. document-hardcopy                       ; not exported
  297. document-hardcopy  print-fn compute-doc-size &key view (show-dialog? t)
  298.    Prints a document. The show-dialog? parameter is present
  299.    for compatibility with the standard method for printing 
  300.    fred-windows and is used to display the print job dialog.
  301.  
  302.    This routine is the basis for picture-hardcopy and window-hardcopy.
  303.    Use document-hardcopy to build other specialized hardcopy routines.
  304.  
  305.    If no printer errors occurred and the user did not cancel
  306.       returns t
  307.    otherwise 
  308.       returns nil indicating an error occurred in printing
  309.  
  310.    The routine performs the following sequence of operations
  311.    1. Opens the printer
  312.    2. Displays the print job dialog box which indicates the method for cancelling.
  313.    3. Retrieves the print record
  314.    4. Determines the page layout using the rectangle corners
  315.       returned by the document-corners function
  316.    5. Opens the printer document
  317.    6. While there are pages to print and the user has not pressed cancel
  318.          For each page in the document that is to be printed, repeats the 
  319.          following steps
  320.             a. opens the page
  321.             b. draws the page using the print-fn
  322.             c. closes the page
  323.    7. Closes the printer document
  324.    8. Closes the printer
  325.    9  If no printer errors occurred and the user did not cancel
  326.          returns t
  327.       otherwise 
  328.          returns nil indicating an error occurred in printing
  329.       Use (get-printer-error) to retrive the printer error condition.
  330.  
  331.     Parameters
  332.     document-corners 
  333.                   Function that computes the corners of the document
  334.                   Parameters:
  335.                        view         the view associated with the document
  336.                        page-size    a point representing the size of the
  337.                                     page-rectangle in pixels
  338.                   Returns the corners of the document rectangle
  339.                   Where the default points are #@(0 0) page-size
  340.                        topleft      the top left corner
  341.                        bottomRight  the bottom right corner
  342.                   If document-corners is not a function, uses the routine
  343.                   default-document-corners which returns the points defining
  344.                   the page rectangle.
  345.  
  346.    print-fn       Function that draws a picture of the document.
  347.                   Parameters:
  348.                        view        suppled by the view keyword. This should be a view
  349.                                    or nil.
  350.                        page-size   the page rectangle size as a point (top left = #@(0 0))
  351.                        page-no     the current page being printed
  352.                        offset      the top left corner of the portion of the document
  353.                   If local, prints the rectangular portion of the document defined 
  354.                      by the points offset (add-points offset page-size). The
  355.                      coordinates are unchanged.
  356.                   Otherwise, adjusts the coordinates by subtracting offset
  357.                      from all points to print within the page rectangle #@(0 0)
  358.                      page-size.
  359.  
  360.                   If print-fn is not a function, uses default-document-hardcopy
  361.                   which does nothing.
  362.  
  363.    :view          the view, default is nil for no view. Passed as a parameter to
  364.                   document-corners and print-fn.
  365.  
  366.    :show-dialog?  display the print job dialog (default t)
  367.  
  368.    :local         default is t. If true, use the document coordinates while printing
  369.                   otherwise use coordinates within the page rectangle,
  370.                   by adjusting all coordinates by offset. 
  371.  
  372. |#
  373.  
  374. (export '(picture-hardcopy print-contents page-setup get-printer-error page-size))
  375. (provide 'print-u)
  376.  
  377. ;; prepare to redefine the functions get-prec and remove-prec by a standard generic function
  378. (progn
  379.   (when (and (fboundp 'get-prec) 
  380.              (equal (type-of #'get-prec) 'function))
  381.     (fmakunbound 'get-prec))
  382.   (when (and (fboundp 'remove-prec)
  383.              (equal (type-of #'get-prec) 'function))
  384.     (fmakunbound 'remove-prec))
  385.   (setq *save-exit-functions*
  386.         (remove 'remove-prec *save-exit-functions* :key #'function-name)))
  387.  
  388. (eval-when (eval load compile)
  389.   (require :resources))
  390.  
  391. #-not-mcl-final 
  392. (eval-when (eval compile) 
  393.   (require :quickDraw))
  394. #+not-mcl-final
  395. (eval-when (eval compile) 
  396.   (ccl::require-interface :printTraps)
  397.   (require :quickDraw)
  398.   (require :loop)                       ; loop is automatically included in MCL 2.0f
  399.   )
  400.  
  401.  
  402. ;; Routines from quickdraw-u.lisp from Michael S. Engber
  403. ;;     Copyright  1991 Northwestern University Institute for the Learning Sciences
  404. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  405.  
  406. ;; the following macros are standard in MCL2.0 final
  407. #+not-mcl-final 
  408. (eval-when (:compile-toplevel :load-toplevel :execute)
  409.   
  410.   (defmacro href (pointer accessor)
  411.     `(rref ,pointer ,accessor :storage :handle))
  412.   
  413.   (defmacro pref (pointer accessor)
  414.     `(rref ,pointer ,accessor :storage :pointer)))
  415.   
  416. (defmacro hset (pointer accessor thing)
  417.   `(rset ,pointer ,accessor ,thing :storage :handle))
  418.  
  419. (defmacro pset (pointer accessor thing)
  420.   `(rset ,pointer ,accessor ,thing :storage :pointer))
  421.  
  422. (defmacro with-font-spec (font-spec &body body)
  423.   (if (and (listp font-spec) (every #'constantp font-spec))
  424.     (multiple-value-bind (ff ms) (font-codes font-spec)
  425.       `(with-font-codes ,ff ,ms ,@body))
  426.     (let ((ff (gensym))
  427.           (ms (gensym)))
  428.       `(multiple-value-bind (,ff ,ms) (font-codes ,font-spec)
  429.          (with-font-codes ,ff ,ms ,@body)))))
  430.  
  431. (defmacro with-pen-state ((&key pnLoc pnSize pnMode pnPat pnPixPat) &body body)
  432.   (let ((state (gensym)))
  433.     `(rlet ((,state :PenState))
  434.        (require-trap #_GetPenState :ptr ,state)
  435.        (unwind-protect
  436.          (progn
  437.            ,@(when pnLoc    `((require-trap #_MoveTo :long ,pnLoc)))
  438.            ,@(when pnSize   `((require-trap #_PenSize :long ,pnSize)))
  439.            ,@(when pnMode   `((require-trap #_PenMode :signed-integer ,pnMode)))
  440.            ,@(when pnPat    `((require-trap #_PenPat :ptr ,pnPat)))
  441.            ,@(when pnPixPat `((require-trap #_PenPixPat :ptr ,pnPixPat)))
  442.            ,@body)
  443.          (require-trap #_SetPenState :ptr ,state)))))
  444. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  445. ;; end of macros from quickdraw.lisp
  446.  
  447. (defun set-page-range (prec pages-to-print)
  448.   (hset prec :tprint.prjob.iFstpage 1)
  449.   (hset prec :tprint.prjob.iLstpage pages-to-print))
  450.  
  451. (defun copy-handle (handle)
  452.   (rlet ((h :pointer))
  453.     (setf (%get-ptr h) handle)
  454.     (#_HandToHand h)
  455.     (%get-ptr h)))
  456.  
  457. (defvar *printing* nil "Printing not in progress")
  458. (defvar *print-record-window* nil "window containg the view being printed")
  459. (defvar *mcl-get-print-record* #'get-print-record)
  460. (defparameter *debug* nil)              ;  for debugging only
  461. (defparameter *print-error* nil "The printing error in the form printer-condition")
  462. (defvar *print-hc-prec*)                ; the default print-record
  463.  
  464. ;; condition for printer errors
  465. (define-condition printer-condition (error)
  466.   (phase code cond)
  467.   (:report (lambda (condition stream)
  468.              (with-slots (phase code cond) condition
  469.                (if cond
  470.                  (format stream "Printer error ~s" cond)  
  471.                  (format stream "Printer error ~s in phase ~s" code phase))))))
  472.  
  473. ;; condition for a user-cancel for a print operation
  474. (define-condition user-cancel (printer-condition))
  475.  
  476.  
  477.  
  478. ;; functions for converting coordinates from one system to another
  479. (defun convert-offset (window container offset)
  480.   ;; If the container is a view, returns in window coordinates, 
  481.   ;; the point offset which is expressed in container coordinates
  482.   ;; Otherwise returns the offset.
  483.   (subtract-points 
  484.    (if container
  485.      (convert-coordinates #@(0 0) container window)
  486.      #@(0 0))
  487.    offset))
  488.  
  489. (defmethod window-view-corners ((self view) &optional (offset #@(0 0)))
  490.   ;; returns the coordinates of the view corners in window coordinates
  491.   ;; offset by offset
  492.   (let ((container (view-container self))
  493.         (window (view-window self)))
  494.     (multiple-value-bind (topLeft bottomRight)
  495.                          (view-corners self)
  496.       (setq offset (convert-offset window container offset))
  497.       (values (add-points topLeft offset) (add-points bottomRight offset)))))
  498.  
  499. (defmethod window-view-corners ((self dialog-item)  &optional (offset #@(0 0)))
  500.   ;; returns the coordinates of the view corners of a dialog item
  501.   ;; in window coordinates offset by offset
  502.   (let ((container (view-container self))
  503.         (window (view-window self)))
  504.     (multiple-value-bind (topLeft bottomRight)
  505.                          (view-corners self)
  506.       (setq offset (convert-offset window container offset))
  507.       (values (add-points topLeft offset) (add-points bottomRight offset)))))
  508.  
  509. ;;; Modified routines from print-utils.lisp for printing the contents of a views
  510. ;;; converted from MCL1.3.2
  511. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  512. ;;
  513. ;;hardcopy.lisp
  514. ;;
  515. ;;
  516. ;;copyright 1988-89 Apple Computer, Inc.
  517. ;;
  518. ;; defines a very basic printing routine for windows
  519. ;;
  520. ;; Code taken from Apple and Bill Kornfeld and played with a bit to get
  521. ;; something working.  Trying to change the wptr and
  522. ;; then doing a view-draw-contents fails --- LISP unexpectantly quits.
  523. ;; view-draw-contents without changing the window pointer
  524. ;; causes a print job to be sent to the printer but nothing comes out.
  525. ;; Using a print-contents function that just makes the appropriate 
  526. ;; calls seems to work ok. The basic print-contents
  527. ;; quickdraw functions for text, views and windows are defined here. 
  528. ;; Some extra print-contents functions for other items is defined in
  529. ;; odin-printing.lisp -- DEH 6/20/91
  530.  
  531. ;;;------------------ Printer constants----------------------------------------
  532. (defconstant $err-printer 94)
  533. (defconstant $err-printer-load 95)
  534. (defconstant $err-printer-start 97)
  535.  
  536. ;;;------------------ Routine for trapping printer errors----------------------
  537. (defun printer-ok (&optional (errnum $err-printer)
  538.                              &aux (print-error (#_prError)))
  539.   ;; Checks for a printer error for the last printer command
  540.   ;; If there was an error, sets *printing* to nil
  541.   ;;   and if there has not been a previous printing error
  542.   ;;   sets the *print-error* to `(,errnum ,error)
  543.   (if (zerop print-error)
  544.     t
  545.     (progn
  546.       (unless *print-error*
  547.         (setq *print-error* (make-condition 'printer-condition))
  548.         (setf (slot-value *print-error* 'phase) errnum
  549.               (slot-value *print-error* 'code) print-error
  550.               (slot-value *print-error* 'cond) nil))
  551.       (setq *printing* nil)
  552.       (signal 'user-cancel))))
  553.  
  554. (defmacro check-printer-ok (form &optional (errnum $err-printer))
  555.   "Checks that the printer is ok after the execution of the form"
  556.   `(progn
  557.      ,form
  558.      (if (printer-ok ,errnum)
  559.        t
  560.        (throw :cancel nil))))
  561.  
  562. (defun get-printer-error ()
  563.   ;; returns nil or the the last non-zero printer error 
  564.   *print-error*)
  565.  
  566. ;;;------------------ The basic print-contents functions-----------------------
  567. (defmethod print-contents ((v window) &optional (offset #@(0 0)))
  568.   "a window draws a box around itself and
  569.    then asks its subviews to print themselves"
  570.   ;;first frame it
  571.   (multiple-value-bind (top-left bottom-right)
  572.                        (window-view-corners v offset)
  573.     (ccl::with-rectangle-arg (r top-Left bottom-right) 
  574.       (#_FrameRect r)))
  575.   (dovector (sv (view-subviews v))
  576.     (print-contents sv offset)))
  577.  
  578. (defmethod print-contents ((v view) &optional (offset #@(0 0)))
  579.   "a view just asks its subviews to print themselves"
  580.     (dovector (sv (view-subviews v))
  581.       (print-contents sv offset)))
  582.  
  583. (defmethod print-contents ((sv ccl::basic-editable-text-dialog-item)
  584.                            &optional (offset #@(0 0)))
  585.   "editable text uses textbox -- takes into account font and the justification"
  586.     (multiple-value-bind (top-left bottom-right)
  587.                          (window-view-corners sv offset)
  588.     (with-font-spec (view-font sv)
  589.       (ccl::with-rectangle-arg (r top-Left bottom-right)
  590.         (with-pstrs ((pstring (dialog-item-text sv)))
  591.           (#_TextBox :ptr (%inc-ptr pstring 1)
  592.            :long (length (dialog-item-text sv))
  593.            :ptr r
  594.            :word (slot-value sv 'ccl::text-justification)))))))
  595.  
  596. (defmethod print-contents ((sv static-text-dialog-item) &optional (offset #@(0 0)))
  597.   "static text uses textbox -- take into account font and the justification"
  598.   (multiple-value-bind (top-left bottom-right)
  599.                        (window-view-corners sv offset)
  600.     (with-font-spec (view-font sv)
  601.       (ccl::with-rectangle-arg (r top-Left bottom-right)
  602.         (with-pstrs ((pstring (dialog-item-text sv)))
  603.           (#_TextBox :ptr (%inc-ptr pstring 1)
  604.            :long (length (dialog-item-text sv))
  605.            :ptr r
  606.            :word (slot-value sv 'ccl::text-justification)))))))
  607.  
  608. (defmethod print-contents ((sv button-dialog-item)  &optional (offset #@(0 0)))
  609.   (multiple-value-bind (top-left bottom-right)
  610.                        (window-view-corners sv offset)
  611.     (ccl::with-rectangle-arg (r top-left bottom-right)
  612.       (with-font-spec (view-font sv)
  613.         (with-pstrs ((pstring (dialog-item-text sv)))
  614.           (#_TextBox :ptr (%inc-ptr pstring 1)
  615.            :long (length (dialog-item-text sv))
  616.            :ptr r :word 1)))
  617.       ;;; end of with-font-spec
  618.       (with-pen-state (:pnSize #@(1 1)
  619.                                :pnMode #$PATOR
  620.                                :pnPat *black-pattern*)
  621.           (decf (rref r :rect.left)
  622.                 (floor (dialog-item-width-correction sv) 2))
  623.           (incf (rref r :rect.right)
  624.                 (floor (dialog-item-width-correction sv) 2))
  625.           (#_FrameRoundRect :ptr r :word 10 :word 6)))))
  626.  
  627. (defmethod print-contents ((sv simple-view) &optional offset)
  628.   (declare (ignore offset))
  629.   "default if all else fails do nothing"
  630.   t)
  631. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  632. ;;; End of modified routines from print-utils.lisp
  633.  
  634. ;;;------------------ handles - checking validity and removing -------------------
  635. (defun valid-handle (handle)
  636.   (when (and handle
  637.              (handlep handle)
  638.              (pointerp handle)
  639.              (macptrp handle)
  640.              (not (equal handle (%null-ptr))))
  641.     handle))
  642.  
  643. (defun dispose-handle (handle)
  644.   (when (valid-handle handle)
  645.       (#_disposeHandle handle)))
  646.  
  647. ;;;---------retrieving and changing the value of an internal print-record---------
  648. ;; routines do not allocate new print records 
  649. (defmethod prec-get ((self view))
  650.   (view-get self :prec))
  651.  
  652. (defmethod prec-get ((self t))
  653.   (when (boundp '*print-hc-prec*)
  654.     *print-hc-prec*))
  655.  
  656. (defmethod prec-put ((self view) value)
  657.   (view-put self :prec value))
  658.  
  659. (defmethod prec-put ((self t) value)
  660.   (setq *print-hc-prec* value))
  661.  
  662. (defmacro clean-catch-cancel (flag &body body)
  663.   ;; When debugging print the flag
  664.   ;; Execute the body unwind-protected while catching
  665.   ;; cancels, errors, aborts and breaks
  666.   (let ((old-state (gensym)))
  667.    `(let ((,old-state *break-on-errors*))
  668.      (unwind-protect
  669.       (handler-case
  670.        (restart-case
  671.          (catch :cancel
  672.            (when *debug* (format t "~&--->~a~%" ,flag))
  673.            (setq *break-on-errors* nil)
  674.            ,@body)
  675.          (abort () (message-dialog "Printing aborted.")
  676.                 (stop-printing))
  677.          (error (condition) (stop-printing condition)))
  678.        (error (condition) (setq *printing* nil) condition))
  679.       (setq *break-on-errors* ,old-state)))))
  680.  
  681. ;;;---------determining the window containing the view (if any)---------
  682. ;;  for views returns
  683. ;;    either the window containing the view
  684. ;;    or the outermost view containing the view
  685. ;;  for all other objects returns the object
  686.  
  687. (defmethod containing-window ((view window))
  688.   view)
  689.  
  690. (defmethod containing-window ((sub-view view))
  691.   (loop with new-view
  692.         do (setq new-view (view-container sub-view))
  693.         while new-view
  694.         do (setq sub-view new-view)
  695.         finally (return sub-view)))
  696.  
  697. (defmethod containing-window ((self t))
  698.   self)
  699.  
  700. ;;;---------allocating, modifying and updating the internal print records---------
  701. (defmethod remove-view-from-window :after ((subview view))
  702.   (remove-prec subview))
  703.  
  704. ;; file names associated with views
  705. (defmethod view-file-name ((window fred-window))
  706.   (slot-value window 'ccl::my-file-name))
  707.  
  708. (defmethod view-file-name ((self t))
  709.   nil)
  710.  
  711. ;;;---------manipulating the internal print records---------
  712. (defmethod remove-prec ((self t))
  713.   ;; clean up the internal tprint handle (if any)
  714.   (dispose-handle (prec-get self))
  715.   (prec-put self nil))
  716.  
  717. (defmethod replace-prec ((self t) new-value)
  718.   ;; clean up the internal tprint handle (if any)
  719.   (let ((old-value (prec-get self)))
  720.     (unless (eq old-value new-value)
  721.       (remove-prec self)
  722.       (prec-put self new-value))
  723.     new-value))
  724.  
  725. (defmethod update-file-prec ((self t) prec &optional file-name)
  726.   ;; Saves a copy of the internal print record as a resource. 
  727.   ;; Called during a page setup and after saving a file (in this
  728.   ;; case the file-name argument is supplied 
  729.   (let ((filename (or file-name (view-file-name self)))
  730.         new-prec
  731.         old-prec)
  732.     (when (valid-handle prec)
  733.       (when (pathnamep filename)
  734.         (with-open-resource-file (refnum filename :if-does-not-exist :create)
  735.           (when *debug* (print-record prec :tprint) (terpri))
  736.           (setq old-prec (get-resource :prec 128 :errorp nil))
  737.           (when (valid-handle old-prec)
  738.             (remove-resource old-prec)
  739.             (dispose-handle old-prec))
  740.           (setq new-prec (copy-handle prec))
  741.           (when *debug* (print-record prec :tprint) (terpri))
  742.           ;; from Inside Macintosh I-123
  743.           (#_HNoPurge new-prec)
  744.           (add-resource new-prec :prec 128) 
  745.           (#_changedResource new-prec)
  746.           (write-resource new-prec)
  747.           (#_HPurge new-prec)
  748.           new-prec)))))
  749.  
  750. (defmethod get-prec ((self t))
  751.   (let (printer-record
  752.         (file-name (view-file-name self))
  753.         (view-print-record (prec-get self))
  754.         create)
  755.     ;; retrieves and possibly initializes the private print record
  756.     ;; if the print record exists and is a valid handle
  757.     ;;   returns the handle
  758.     ;; otherwise initializes the private print record
  759.     ;;   tries to read the :prec resource from the view-file-name
  760.     ;;    if successful
  761.     ;;     stores and returns a copy of the resource (handle)  
  762.     ;;    otherwise
  763.     ;;     creates a default print record using default-prec
  764.     ;;  
  765.     (cond 
  766.      ((valid-handle view-print-record) view-print-record)
  767.      ((null (pathnamep file-name)) (create-default-prec self))
  768.      (t (with-open-resource-file (refnum file-name :if-does-not-exist nil)
  769.           (cond 
  770.            ((or (null refnum) 
  771.                 (null (setq printer-record (get-resource :prec 128 :errorp nil))))
  772.             (setq view-print-record (create-default-prec self)
  773.                   create t))
  774.            (t (remove-prec self)
  775.               (setq view-print-record (copy-record printer-record :tprint))
  776.               (replace-prec self view-print-record)))
  777.           (when create
  778.             (update-file-prec self view-print-record))
  779.           view-print-record)))))
  780.  
  781. (defmethod create-default-prec ((self t))
  782.   (let (view-print-record)
  783.     (remove-prec self)
  784.     (setq view-print-record (default-prec self))
  785.     (replace-prec self view-print-record)
  786.     (update-file-prec self view-print-record)
  787.     view-print-record))
  788.  
  789. (defmethod get-print-prec ((self t))
  790.   (let ((outer-container (containing-window self)))
  791.     (cond ((null outer-container) (get-prec t))
  792.           ((eq self outer-container) (get-prec self))
  793.           (outer-container (get-prec outer-container))
  794.           (t (get-prec t)))))
  795.  
  796. ;; create a default print-record
  797. (defmethod default-prec ((self t))
  798.   (let (code
  799.         view-print-record)
  800.     (clean-catch-cancel 
  801.       :prec
  802.       (remove-prec self)
  803.       (setq view-print-record (#_NewHandle :errchk (record-length :TPrint)))
  804.       (setq code (#_MemError))
  805.       (when (zerop code)
  806.         (replace-prec self view-print-record)
  807.         (if (not (valid-handle view-print-record))
  808.           (setq code "invalid-handle")
  809.           (progn
  810.             (check-printer-ok (#_PrintDefault :ptr view-print-record))
  811.             (setq code nil)))))
  812.     (if code
  813.       (remove-prec self)
  814.       view-print-record)))
  815.  
  816. ;; routines for allocating/deallocating the tprint handle for printing
  817.  
  818. (defun stop-printing (&optional condition)
  819.   ;; stop printing
  820.   (setq *printing* nil
  821.         *print-error* (make-condition 'printer-condition))
  822.   (if condition
  823.     (setf (slot-value *print-error* 'phase) nil
  824.           (slot-value *print-error* 'code) nil
  825.           (slot-value *print-error* 'cond) condition)
  826.     (setf (slot-value *print-error* 'phase) $err-printer
  827.           (slot-value *print-error* 'code) #$iPrAbort
  828.           (slot-value *print-error* 'cond) nil))
  829.   (#_PrSetError #$iPrAbort)
  830.   (error *print-error*))
  831.  
  832. (defun reset-printing ()
  833.   (setq *printing* nil)
  834.   (#_prSetError #$NoErr))
  835.  
  836. ;; the method for getting a fred print record
  837. (defmethod get-print-prec ((window fred-window))
  838.   (get-print-record))
  839.  
  840. (defmethod check-print-prec ((self t))
  841.   ;; gets the tprint handle and validates it 
  842.   ;; when successful, returns the tprint handle
  843.   ;; must be called when the printer is open (e.g. within with-printer-open)
  844.   (let ((local-prec (get-print-prec self)))
  845.     (when local-prec
  846.       (clean-catch-cancel 
  847.        :check-print
  848.        (check-printer-ok (#_prValidate :ptr local-prec :boolean))
  849.        local-prec))))
  850.  
  851. ;; the print status dialog box (print-dialog) displayed when printing in progress.
  852. (defclass print-dialog (window)
  853.   ()
  854.   (:default-initargs
  855.     :window-type :double-edge-box 
  856.     :view-position :centered 
  857.     :view-size #@(373 96) 
  858.     :close-box-p nil 
  859.     :view-font '("Chicago" 12 :srcor :plain)))
  860.  
  861. (defmethod initialize-instance ((window print-dialog) &rest initargs)
  862.   (apply #'call-next-method window initargs)
  863.   (add-subviews window
  864.                 (make-instance 'static-text-dialog-item
  865.                   :view-position #@(10 10)
  866.                   :view-size #@(151 40) 
  867.                   :dialog-item-text (format nil
  868.                                             "Printing in progress
  869. To cancel press ~a-." #\CommandMark)
  870.                   :view-nick-name 'title)
  871.                 
  872.                 (make-instance 'static-text-dialog-item 
  873.                   :view-position #@(10 72) 
  874.                   :view-size #@(120 18) 
  875.                   :dialog-item-text "Printing page")
  876.                 
  877.                 (make-instance 'static-text-dialog-item 
  878.                   :view-position #@(135 72) 
  879.                   :view-size #@(36 18) 
  880.                   :dialog-item-text ""
  881.                   :view-nick-name 'page)
  882.                 
  883.                 #|
  884. (make-instance 'button-dialog-item 
  885.   :view-position #@(302 72) 
  886.   :view-size #@(62 16) 
  887.   :dialog-item-text "Cancel" 
  888.   :dialog-item-action 
  889.   #'(lambda (item) item
  890.      (window-hide (view-window item))
  891.      (stop-printing)) 
  892.   :default-button nil)
  893. |#
  894.                 ))
  895.  
  896. (defvar *print-dialog*
  897.   (make-instance 'print-dialog :window-show nil)
  898.   "The printing progress dialog box")
  899.  
  900. ;; gets the dialog box asscoiated with print progress
  901. (defmethod get-print-dialog ((self t) &key (display nil) (wait t))
  902.   (declare (ignore self))
  903.   "Displays the printer progress dialog box and waits for 1 second."
  904.   (unless (and *print-dialog* (wptr *print-dialog*) (pointerp (wptr *print-dialog*)))
  905.     (setq *print-dialog* (make-instance 'print-dialog :window-show nil)))
  906.   (when (and *printing* display) 
  907.     (with-focused-view *print-dialog*
  908.       (window-show *print-dialog*)))
  909.   (when wait (sleep 1))
  910.   *print-dialog*)
  911.  
  912. ;; default method for removing the print progress dialog box, 
  913. ;; specialize for other views
  914. (defmethod remove-print-dialog ((self t))
  915.   (when (and *print-dialog* (wptr *print-dialog*))
  916.     (window-close *print-dialog*))
  917.   (setq *print-dialog* nil))
  918.  
  919. ;; default method for indicating printing progress, specialize for other views
  920. ;; Note: does not update the page field when background printing is off
  921. (defmethod set-page-number ((self t) page-no &key (display nil))
  922.   "Update the page number field for printing"
  923.   (let* ((print-dialog (get-print-dialog self :display display :wait display))
  924.          (page-field (view-named 'page print-dialog)))
  925.     ; force the window to be updated
  926.     (with-focused-view print-dialog
  927.       (set-dialog-item-text page-field (format nil "~3d" page-no))
  928.       ;(event-dispatch)    ; fails to return when background printing is off
  929.       (sleep 1))))            
  930.  
  931. ;; methods and functions for working with the printer port as a view
  932. ;;  similar to the wmgr-view functions in oodles-of-utils:simple-view-ce.lisp
  933. ;; Supplied by Bill St. Clair at Apple.
  934.  
  935. (defclass printer-view (simple-view)
  936.   ((clip-region :initform nil :accessor printer-view-clip-region)))
  937.  
  938. (defmethod view-origin ((view printer-view))
  939.   (let ((wptr (wptr view)))
  940.     (if wptr
  941.       (rref wptr :grafport.portrect.topleft)
  942.       #@(0 0))))
  943.  
  944. (defmethod view-clip-region ((view printer-view))
  945.   (let ((macptr (printer-view-clip-region view)))
  946.     (unless (typep macptr 'macptr)
  947.       (setq macptr
  948.             (setf (printer-view-clip-region view) (%null-ptr))))
  949.     (%setf-macptr macptr (rref (wptr view) :grafport.cliprgn))
  950.     macptr))
  951.  
  952. (defun make-printer-view (printer-port)
  953.   (let ((topleft (rref printer-port :grafport.portrect.topleft))
  954.         (botright (rref printer-port :grafport.portrect.botright)))
  955.     (make-instance 'printer-view
  956.       :wptr printer-port
  957.       :view-position topleft
  958.       :view-size (subtract-points botright topleft))))
  959.  
  960. ;;  basic macros for using a printer, printing a document and printing a page.
  961. (defmacro with-open-page ((hardcopy-ptr page-size offset &key (local t))
  962.                           &rest body)
  963.   ;; Opens a printer page
  964.   ;; executes the body
  965.   ;; closes the printer upon termination (even when in error)
  966.   ;; returns the result of executing the body
  967.   (let ((r (gensym))
  968.         (vals (gensym)))
  969.     `(let (,vals)
  970.        (clean-catch-cancel 
  971.         :open-page
  972.         (rlet ((,r :rect :topLeft #@(0 0) :bottomRight ,page-size))
  973.           (when ,local (require-trap #_offsetRect :ptr ,r :long ,offset))
  974.           (unwind-protect
  975.             (clean-catch-cancel 
  976.              :inner-open-page
  977.              (setq ,vals
  978.                    (multiple-value-list
  979.                     (with-clip-rect ,r 
  980.                       (check-printer-ok 
  981.                        (require-trap #_PrOpenPage
  982.                                      :ptr ,hardcopy-ptr :ptr (if ,local ,r  (%null-ptr))))
  983.                       ,@body))))
  984.             (check-printer-ok (require-trap #_PrClosePage :ptr ,hardcopy-ptr)))))
  985.        (values-list ,vals))))
  986.  
  987. (defmacro with-open-doc (hardcopy-ptr prec &rest body)
  988.   ; _PrOpenDoc puts up a dialog window
  989.   ; In order to process events within the body, we must call
  990.   ; event-dispatch, otherwise windows will not be updated
  991.   ; Opens the printer document
  992.   ; Executes the body of code with the local variable
  993.   ;   hardcopy-ptr bound to the printer GrafPort
  994.   ;   prec is a handle to the TPrint record
  995.   ; Closes the printer document upon termination (even when in error)
  996.   ; Returns the result of executing the body
  997.   ;;
  998.   ; without-interrupts appears in the same place as (window-hardcopy fred-window)
  999.   ; before the open-doc (decinest appears at location 332, open-doc at 360-362)
  1000.   (let ((vals (gensym))
  1001.         (stRec (gensym))
  1002.         (printer-view (gensym)))
  1003.     `(let ((,hardcopy-ptr 
  1004.             (require-trap #_PrOpenDoc :ptr ,pRec :ptr (%null-ptr) :ptr (%null-ptr) :ptr))
  1005.            ,vals
  1006.            ,printer-view)
  1007.        (without-interrupts
  1008.         (clean-catch-cancel 
  1009.           :open-doc
  1010.           (unwind-protect
  1011.             (clean-catch-cancel 
  1012.               :port
  1013.               (setq ,printer-view (make-printer-view ,hardcopy-ptr))
  1014.               (check-printer-ok nil $err-printer-start)
  1015.               (setq ,vals
  1016.                     (multiple-value-list
  1017.                      (with-focused-view ,printer-view 
  1018.                        ,@body))))
  1019.             (check-printer-ok (require-trap #_PrCloseDoc :ptr ,hardcopy-ptr)))
  1020.           (when (= (href ,prec :tprint.prJob.bjDocLoop) #$bSpoolLoop)
  1021.             (%stack-block ((,StRec (record-length :tprStatus)))
  1022.               (check-printer-ok (require-trap #_PrPicFile
  1023.                                  :ptr ,pRec
  1024.                                  :ptr (%null-ptr)
  1025.                                  :ptr (%null-ptr)
  1026.                                  :ptr (%null-ptr)
  1027.                                  :ptr ,StRec)))))
  1028.         (values-list ,vals)))))
  1029.  
  1030. (defmacro with-open-printer ((prec &key (view t) (show-dialog? nil)) &rest body)
  1031.   ; Opens the printer
  1032.   ; Executes the body of code with the local variable
  1033.   ;  Closes the printer upon termination (even when in error)
  1034.   ;; returns the result of executing the body
  1035.   
  1036.   (let ((vals (gensym)))
  1037.     `(let (,vals ,prec)
  1038.        (unwind-protect
  1039.          (clean-catch-cancel 
  1040.           :open-print
  1041.           (setq ,vals
  1042.                 (multiple-value-list
  1043.                  (unless *printing*
  1044.                    (check-printer-ok (require-trap #_PrOpen) $err-printer-load)
  1045.                    (setq *printing* t)
  1046.                    (when (and (setq ,prec (get-print-prec ,view))
  1047.                               (check-print-prec ,view)
  1048.                               (or (null ,show-dialog?) 
  1049.                                   (with-cursor *arrow-cursor* 
  1050.                                     (require-trap #_PrJobdialog :ptr ,prec :boolean))))
  1051.                      ,@body)))))
  1052.          (check-printer-ok (require-trap #_PrClose))
  1053.          (setq *printing* nil))
  1054.        (values-list ,vals))))
  1055.  
  1056. ;; generalized page-setup routines for objects that are not fred windows
  1057. (defmethod page-setup ((self t))
  1058.   ;; Atempts to retrieve a valid tprint handle
  1059.   ;; If successful displays the page setup dialog using the print record
  1060.   ;; Returns t when successful
  1061.   (with-cursor *arrow-cursor*
  1062.     (with-open-printer (prec :view self)
  1063.       (when *debug* (print-record prec :tprint) (terpri))
  1064.       (check-printer-ok (#_PrStlDialog :ptr prec :boolean))
  1065.       (update-file-prec self prec)
  1066.       (when *debug* (print-record prec :tprint) (terpri))
  1067.       t)))
  1068.  
  1069. ;; page setup
  1070. ;;   for fred windows
  1071. (defmethod page-setup ((window fred-window))
  1072.   (let ((*print-record-window* window))
  1073.     (print-style-dialog)))
  1074.  
  1075. ;; routines for determining the topLeft and bottomRight corners
  1076. ;; of the printer-page
  1077. (defun get-page-size (pRec)
  1078.   (subtract-points (href pREC :tprint.prInfo.rpage.bottomRight)
  1079.                    (href pREC :tprint.prInfo.rpage.topLeft)))
  1080.  
  1081. (defmethod page-size ((self t))
  1082.   (with-open-printer (prec :view self)
  1083.     (get-page-size prec)))
  1084.  
  1085. (defmethod page-size ((window fred-window))
  1086.   (with-open-printer (prec :view window)
  1087.     (get-page-size prec)))
  1088.      
  1089. ;; Routines for computing the corners of rectangular pictures and windows
  1090.  
  1091. (defun picture-corners (picture page-size)
  1092.   (declare (ignore page-size))
  1093.   ;; return the topleft and bottomRight corners of the picture
  1094.   (when (handlep picture)
  1095.     (values
  1096.      (rref picture picture.picframe.topleft)
  1097.      (rref picture picture.picframe.bottomRight))))
  1098.  
  1099. (defmethod window-document-corners ((view window) page-size)
  1100.   (declare (ignore page-size))
  1101.   ;; Computes the topLeft and bottomRight corners of the rectangle
  1102.   ;; for the view. Specialize to handle scrolling windows
  1103.   (view-corners view))
  1104.  
  1105. (defmethod view-document-corners ((view view) page-size)
  1106.   (declare (ignore page-size))
  1107.   ;; Computes the topLeft and bottomRight corners of the rectangle
  1108.   ;; for the view. Specialize to handle scrolling windows
  1109.   (view-corners view))
  1110.  
  1111. ;; routines for computing the page layout (document size in pages-h x pages-v)
  1112. (defun compute-page-size (document-size page-size)
  1113.   ;; returns the point representing the document-size in pages width x depth
  1114.   (let* ((page-h (ceiling (point-h document-size) (point-h page-size)))
  1115.          (page-v (ceiling (point-v document-size) (point-v page-size))))
  1116.     (values
  1117.      page-h
  1118.      page-v
  1119.      (* page-h page-v))))
  1120.  
  1121. ;; not currently used, can be used within the print-fn for a document-hardcopy
  1122. ;; to determine the current page number, and row/column index
  1123. (defun compute-page-topLeft (page-size pages-h pages-v page-no)
  1124.   ;; given the size of the page-rectangle (page-size)
  1125.   ;;       the dimensions of the document in pages pages-h x pages-v
  1126.   ;;       the page number being printed
  1127.   ;; returns the page-no and the column/row position of the page
  1128.   ;;       and the coordinates of the upper left corner of the
  1129.   ;;       document corresponding to the page of size page-size
  1130.   (declare (ignore pages-v))
  1131.   (multiple-value-bind (real-v real-h)
  1132.                        (truncate page-no pages-h)
  1133.     (values
  1134.      page-no
  1135.      real-h
  1136.      real-v
  1137.     (make-point (* (point-h page-size) real-h)
  1138.                 (* (point-v page-size) real-v)))))
  1139.  
  1140. ;; default routines for printing a document and for determining its size
  1141. (defun default-document-hardcopy (view page-size page-no offset local)
  1142.   (declare (ignore view prRec page-size page-no offset local)))
  1143.  
  1144. (defun default-document-corners (view psize)
  1145.   (declare (ignore view))
  1146.   (values #@(0 0) psize))
  1147.  
  1148. (defun compute-page-layout (view page-size compute-doc-size)
  1149.   ;; uses the compute-doc-size function with view and page-size
  1150.   ;; to compute the size of the document in pages (pages-h x pages-v)
  1151.     (multiple-value-bind (top bottom)
  1152.                          (funcall (if (functionp compute-doc-size)
  1153.                                     compute-doc-size
  1154.                                     #'ccl::default-document-corners)
  1155.                                   view page-size)
  1156.       (compute-page-size (subtract-points bottom top) page-size)))
  1157.  
  1158.  
  1159. ;; hardcopy routines for documents, windows and pictures
  1160.  
  1161. ;;  General hardcopy routine
  1162. (defun document-hardcopy (print-fn document-corners &key (show-dialog? t) view (local t))
  1163.   (setq *print-error* nil)
  1164.   (let (offset 
  1165.         page-size v-dim h-dim (page-no 0))
  1166.     (get-print-dialog view)
  1167.     (with-cursor *arrow-cursor* 
  1168.       (with-open-printer (prec :view view :show-dialog? show-dialog?)
  1169.         (with-cursor *watch-cursor*
  1170.           (when *printing*
  1171.             (clean-catch-cancel 
  1172.              :doco
  1173.               (unwind-protect
  1174.                 (setq page-size (get-page-size prec))
  1175.                 (multiple-value-bind (pages-h pages-v pages)
  1176.                                      (compute-page-layout view page-size document-corners)
  1177.                   (decf pages-h)
  1178.                   (decf pages-v)
  1179.                   (unless (functionp print-fn)
  1180.                     (setq print-fn #'default-document-hardcopy))
  1181.                   (window-select (get-print-dialog view :display t))
  1182.                   (event-dispatch)
  1183.                   (with-open-doc hardcopy-ptr prec
  1184.                     (let* ((from-page (max 1 (href prec :tprint.prJob.iFstPage)))
  1185.                            (to-page (min pages (href prec :tprint.prJob.iLstPage)))
  1186.                            (pages-to-print (1+ (- to-page from-page))))
  1187.                       ;; print pages-to-print pages (from from-page to to-page)
  1188.                       ;; adjust the print record to print only pages-to-print pages
  1189.                       (set-page-range prec pages-to-print)
  1190.                       (loop for v-page fixnum from 0 to pages-v
  1191.                             do (setq v-dim (* (point-v page-size) v-page))
  1192.                             (loop for h-page fixnum from 0 to pages-h
  1193.                                   do (incf page-no)
  1194.                                   (when (<= from-page page-no to-page)
  1195.                                     ;; only print pages in the range from-page to to-page
  1196.                                     (decf pages-to-print)
  1197.                                     (setq h-dim (* (point-h page-size) h-page))
  1198.                                     (setq offset (make-point h-dim v-dim))
  1199.                                     (when *printing*
  1200.                                       (set-page-number view page-no :display t)
  1201.                                       (with-open-page (hardcopy-ptr page-size offset :local local)
  1202.                                         (funcall print-fn view page-size page-no offset local))))
  1203.                                   
  1204.                                   while (and *printing*   ; stop when printing canceled
  1205.                                              (> pages-to-print 0)))   ; or no pages to print
  1206.                             
  1207.                             ; stop when no pages remain to print or printing is cancelled
  1208.                             while (and *printing* (> pages-to-print 0)))))))))
  1209.           (unless *printing* 
  1210.             (unless *print-error*
  1211.               (setq *print-error* (make-condition 'printer-condition))
  1212.               (with-slots (phase code cond) *print-error*
  1213.                 (setq phase $err-printer
  1214.                       code #$iPrAbort
  1215.                       cond nil))
  1216.               (#_PrSetError #$iPrAbort)))
  1217.           (remove-print-dialog view)
  1218.           (setq *printing* nil)
  1219.           (null *print-error*))))))
  1220.  
  1221. ;; Internal routine for printing the contents of a views
  1222. (defmethod view-print-contents ((subview view)
  1223.                                 page-size page-no offset local)
  1224.   (declare (ignore page-size page-no))
  1225.   (let ((*print-record-window* subview))
  1226.     (print-contents subview (if local #@(0 0)
  1227.                                 offset))))
  1228.  
  1229. ;; Print contents of a non-fred window, fred windows already defined
  1230. (defmethod window-hardcopy ((v window) &optional (show-dialog? t))
  1231.   (document-hardcopy #'view-print-contents #'window-document-corners
  1232.                      :view  v
  1233.                      :show-dialog? show-dialog?
  1234.                      :local t))
  1235.  
  1236. ;; Print a picture on the printer
  1237. (defun picture-hardcopy (picture &optional (show-dialog? t))
  1238.   (when (handlep picture)
  1239.     (with-dereferenced-handles ((picture-ptr picture))
  1240.       (flet ((pict-draw (view page-size page-no offset local)
  1241.                (declare (ignore view page-no))
  1242.                (multiple-value-bind (topLeft bottomRight)
  1243.                                     (picture-corners picture page-size)
  1244.                  (with-rectangle-arg (r topLeft bottomRight)
  1245.                    (unless local (#_offsetRect :ptr r :long (subtract-points #@(0 0) offset)))
  1246.                    (#_drawPicture :ptr picture :ptr r))))
  1247.              (pict-size (view page-size)
  1248.                (declare (ignore view))
  1249.                (picture-corners picture page-size)))
  1250.         (declare (dynamic-extent #'pict-draw #'pict-size))
  1251.         (document-hardcopy #'pict-draw #'pict-size :show-dialog? show-dialog?)))))
  1252.  
  1253. ;;;; functions to setup the environment for printing
  1254. ;; changes the page setup menu item to use the new Page Setup function
  1255. (defun fix-file-menu ()
  1256.   (let ((page-setup (find-menu-item *file-menu* "Page Setup"))
  1257.         (print (find-menu-item *file-menu* "Print")))
  1258.     (when page-setup
  1259.       (change-class page-setup 'window-menu-item)
  1260.       (setf (menu-item-action-function page-setup)
  1261.             #'(lambda (window)
  1262.                 (eval-enqueue `(page-setup ,window)))))
  1263.     (when print
  1264.       (setf (menu-item-action-function print)
  1265.             #'(lambda (window)
  1266.                 (eval-enqueue `(ccl::window-hardcopy ,window)))))
  1267.     (setq *printing* nil)))
  1268.  
  1269. (defun remove-hc-prec ()
  1270.   ;; clean up the internal tprint handle
  1271.   ;; modify if you need to clean up others
  1272.   (remove-prec t))
  1273.                 
  1274. (defun setup-printing ()
  1275.   ;; remove and then add #'fix-file-menu to end of *lisp-startup-functions*
  1276.   (setq *lisp-startup-functions*
  1277.         (remove 'fix-file-menu *lisp-startup-functions* :key #'function-name))
  1278.   (setq *printing* nil)
  1279.   (push #'fix-file-menu *lisp-startup-functions*)
  1280.   (setq *save-exit-functions*
  1281.         (remove 'remove-hc-prec *save-exit-functions* :key #'function-name))
  1282.   (push #'remove-hc-prec *save-exit-functions*))
  1283.   
  1284. ;; setup the printing enviroment and fix the Page setup menu item
  1285. (setup-printing)
  1286. (fix-file-menu)
  1287.  
  1288. ;; augment the window-hardcopy, window-save, print-style-dialog
  1289. ;; and get-print-record routines
  1290. (advise ccl::window-hardcopy
  1291.         (let* ((*print-record-window* (car arglist))
  1292.                (*hc-prec* (with-open-printer (prec :view *print-record-window*)
  1293.                             (get-print-prec *print-record-window*))))
  1294.           (:do-it))
  1295.         :when :around)
  1296.  
  1297. (advise ccl::window-save-file
  1298.         (let ((*print-record-window* (car arglist))
  1299.               window-file)
  1300.           (setq window-file (:do-it))
  1301.           (when window-file
  1302.             (with-open-printer (prec :view *print-record-window*)
  1303.               (get-print-prec *print-record-window*)
  1304.               (update-file-prec *print-record-window* 
  1305.                            (get-prec *print-record-window*)
  1306.                            window-file)))
  1307.           window-file)
  1308.         :when :around)
  1309.  
  1310. (advise ccl::print-style-dialog
  1311.         (let ((*print-record-window* (front-window))
  1312.               result)
  1313.           (setq result (:do-it))
  1314.           (with-open-printer (prec :view *print-record-window*)
  1315.             (get-print-prec *print-record-window*)
  1316.             (update-file-prec *print-record-window* (prec-get *print-record-window*)))
  1317.           result)
  1318.         :when :around)
  1319.  
  1320. (let ((*warn-if-redefine* nil)
  1321.       (*warn-if-redefine-kernel* nil))
  1322.   
  1323.   (defun get-print-record ()
  1324.     (if *print-record-window*
  1325.       (get-prec *print-record-window*)
  1326.       (funcall *mcl-get-print-record*)))
  1327.   
  1328.   )
  1329.  
  1330.  
  1331. #|
  1332. (defun make-print-demo ()
  1333.   "Create the experiment application"
  1334.   (let ((target-appl (choose-new-file-dialog :directory "ccl;print-demo")))
  1335.     (save-application target-appl
  1336.                       :excise-compiler nil    ; do want the compiler
  1337.                       :creator :glop
  1338.                       :clear-clos-caches nil ; otherwise we can't access classes
  1339.                       )))
  1340. (make-print-demo)
  1341. |#
  1342.  
  1343. #|
  1344. ;;;  Four printing examples and two examples of saving private print records
  1345. ;;;
  1346. ;;;  Four printing examples:
  1347. ;;;  - contents of a small window
  1348. ;;;  - a picture
  1349. ;;;  - contents of a large window
  1350. ;;;  - a general document
  1351.  
  1352. (defvar *w1*)
  1353. (defvar *test-window*)
  1354. (defvar *picture*)
  1355.  
  1356.  
  1357.  
  1358. ;;---------------------- printing the contents of a small window ------------------------
  1359. ;; Create a window with nested views and print it.
  1360. (setq *w1* (make-instance 'window
  1361.             :window-title "HI there"
  1362.             :view-size #@(300 300)
  1363.             :view-subviews
  1364.                (list (make-instance 'view
  1365.                    :view-position #@(20 20)
  1366.                    :view-size #@(150 130)
  1367.                    :view-subviews
  1368.                        (List (make-instance 'static-text-dialog-item
  1369.                                  :view-position #@(10 10)
  1370.                                  :view-size #@(130 40)
  1371.                                  :view-font '("Helvetica" :srcor :bold 12)
  1372.                                  :dialog-item-text
  1373.                                     "how now said the big brown cow")
  1374.                              (make-instance 'static-text-dialog-item
  1375.                                             :view-position #@(10 70)
  1376.                                             :view-size #@(130 60)
  1377.                                             :view-font '("Geneva" :srcor :underline 14)
  1378.                                             :dialog-item-text
  1379.                                             "there is a bunch of green cheese here on the moon")))
  1380.                      (make-instance 'button-dialog-item
  1381.                                             :view-position #@(160 160)
  1382.                                             :view-size #@(72 16)
  1383.                                             :dialog-item-text "Green"))))
  1384.  
  1385. (window-hardcopy *w1*)                  ; print the window
  1386.                                         ; Also select the window and do a file Print
  1387.  
  1388. ;;---------------------------- printing a picture -----------------------------
  1389. ;; Print a picture. The picture corresponds to a picture of the print-contents
  1390. ;; of the window w1 using a window twice the size. 
  1391. (let ((view-size (view-size *w1*)) mid-point)
  1392.   (when (and (boundp '*picture*) (handlep *picture*))
  1393.     (kill-picture *picture*))
  1394.   (with-focused-view *w1*
  1395.     (start-picture *w1* #@(0 0) (make-point (* 2 (point-h view-size))
  1396.                                             (* 2 (point-v view-size))))
  1397.     (print-contents *w1*)
  1398.     (setq *picture* (get-picture *w1*)))
  1399.  
  1400.   ;; draw the picture at half- in the bottom right corner of *w1*
  1401.   (window-select *w1*)
  1402.   (sleep 1)
  1403.   (setq mid-point (make-point (floor (point-h view-size) 2)
  1404.                               (floor (point-v view-size) 2)))
  1405.   (draw-picture *w1* *picture* mid-point (add-points (view-size *w1*) mid-point))
  1406.   (sleep 1)
  1407.   (print-record *picture* :picture) (terpri)
  1408.   (picture-hardcopy *picture*)              ; print the picture
  1409.   (kill-picture *picture*)                  ; remove the picture
  1410.   )
  1411.  
  1412.  
  1413. ;;;  - 
  1414. ;;-------------------- printing the contents of a large window ---------------------
  1415. ;;  Print the contents of a large dialog (918 x 708) 
  1416. (setq *test-window*
  1417.    (make-instance 'color-dialog
  1418.                :window-type :document-with-zoom 
  1419.                :view-position #@(100 100)
  1420.                :view-size #@(918 708)
  1421.                :view-font '("Chicago" 12 :SRCOR :PLAIN)
  1422.                :view-subviews
  1423.                (list (make-instance 'static-text-dialog-item
  1424.                                        :view-position #@(13 9)
  1425.                                        :view-size #@(56 16)
  1426.                                        :dialog-item-text "Untitled")
  1427.  
  1428.                      (make-instance 'editable-text-dialog-item
  1429.                                        :view-position #@(15 25)
  1430.                                        :view-size #@(84 16)
  1431.                                        :dialog-item-text "Untitled"
  1432.                                        :allow-returns nil)
  1433.  
  1434.                      (make-instance 'button-dialog-item
  1435.                                        :view-position #@(15 47)
  1436.                                        :view-size #@(62 16)
  1437.                                        :dialog-item-text "Untitled"
  1438.                                        :default-button nil)
  1439.  
  1440.                      (make-instance 'editable-text-dialog-item
  1441.                                        :view-position #@(381 683)
  1442.                                        :view-size #@(114 16)
  1443.                                        :dialog-item-text "bottom center"
  1444.                                        :allow-returns nil)
  1445.  
  1446.                      (make-instance 'editable-text-dialog-item
  1447.                                        :view-position #@(11 688)
  1448.                                        :view-size #@(84 16)
  1449.                                        :dialog-item-text "bottom left"
  1450.                                        :allow-returns nil)
  1451.  
  1452.                      (make-instance 'editable-text-dialog-item
  1453.                                        :view-position #@(375 20)
  1454.                                        :view-size #@(84 16)
  1455.                                        :dialog-item-text "top center"
  1456.                                        :allow-returns nil)
  1457.  
  1458.                      (make-instance 'editable-text-dialog-item
  1459.                                        :view-position #@(799 676)
  1460.                                        :view-size #@(84 16)
  1461.                                        :dialog-item-text "bottom right"
  1462.                                        :view-font
  1463.                                        '("New Century Schlbk"
  1464.                                          12 :SRCOR :PLAIN)
  1465.                                        :allow-returns nil)
  1466.  
  1467.                      (make-instance 'editable-text-dialog-item
  1468.                                        :view-position #@(818 20)
  1469.                                        :view-size #@(84 16)
  1470.                                        :dialog-item-text "top right"
  1471.                                        :view-font
  1472.                                        '("New Century Schlbk"
  1473.                                          12 :SRCOR :PLAIN)
  1474.                                        :allow-returns nil)))
  1475. )
  1476.  
  1477. (window-hardcopy *test-window*)           ; print the large dialog
  1478.  
  1479. ;;---------------------- printing a general document -----------------------
  1480. ;;  Print a document of size 552 x 1460 pixels
  1481. ;;  This requires two 8.5" x 11" pages at normal size (Reduce/Enlarge 100%)
  1482. ;;  At normal size prints two pages with 
  1483. ;;  "Now is the time for all good men to come to the aid" on the first page
  1484. ;;  twice on the first page at #@(50 50) and #@(50 100)
  1485. ;;  and with the string "When johnny comes marching home again" in the
  1486. ;;  relative positions #@(200 0) and #@(50 100) on the second page.
  1487. ;;  At 50% or smaller reduction, prints only the first page, reduced.
  1488. ;;  At 200% or greater reduction prints two pages, enlarged.
  1489.  
  1490. ;;  When 50% reduction, prints only one "page"
  1491. (defun my-hardcopy-fn (view page-size page-no offset local)
  1492.   (declare (ignore view page-size))
  1493.   (unless local (setq offset #@(0 0)))
  1494.   (let ((text "Now is the time for all good men to come to the aid"))
  1495.     (with-font-spec '("Times" 18 :srcor :plain)
  1496.       (if (= page-no 0)
  1497.         (#_moveTo :long (add-points #@(50 50) offset))
  1498.         (progn (#_moveTo :long (add-points #@(200 0) offset))
  1499.                (setq text "When johnny comes marching home again")))
  1500.       (with-returned-pstrs ((text-buff text))
  1501.         (#_DrawText :ptr text-buff :integer 1 :integer (length text)))
  1502.       (#_moveTo :long (add-points #@(50 100) offset))
  1503.       (with-returned-pstrs ((text-buff text))
  1504.         (#_DrawText :ptr text-buff :integer 1 :integer (length text)))
  1505.       )))
  1506.  
  1507. (defun my-document-corners (view page-size)
  1508.   (declare (ignore view page-size))
  1509.   ;; a document on 8.5 x 11 paper 1 wide and 2 high
  1510.   (values #@(0 0) (make-point 552 (* 2 730))))
  1511.  
  1512. (document-hardcopy #'my-hardcopy-fn #'my-document-corners)   ; print the document
  1513.  
  1514. ;;;  - 
  1515. ;;-------------------- changing the page setup atributes of a file ---------------------
  1516. ;; open an existing file in a fred window,
  1517. ;; change the page setup attributes and reopen the file 
  1518. (defvar *test-window*)
  1519. (defvar *file-name*)
  1520. (setq *test-window* (fred (choose-file-dialog :button-string "Edit")))
  1521. (setq *file-name* (view-file-name *test-window*))
  1522.  
  1523. ;; Change the page setup   
  1524. (page-setup *test-window*)
  1525. (window-close *test-window*)
  1526.  
  1527. ;; open the file again and see that the attributes have changed
  1528. (setq *test-window* (fred *file-name*))
  1529. (page-setup *test-window*)
  1530.  
  1531. ;; open the file and see that the :prec resource has been saved
  1532. (with-open-resource-file (refnum *file-name* :if-does-not-exist nil)
  1533.   (let (printer-record)
  1534.     (setq printer-record (get-resource :prec 128 :errorp nil))
  1535.     (print-db printer-record)
  1536.     (when (valid-handle printer-record)
  1537.       (print-record printer-record :tprint))))
  1538.  
  1539. ;;;  - 
  1540. ;;-------------------- views that store their print record in a slot ---------------------
  1541. ;;  the slot is ccl::my-print-record
  1542.  
  1543. (defclass print-view (view)
  1544.   ((my-print-record :initform nil)
  1545.    (my-file-name :initform nil)))
  1546.  
  1547. (defclass print-window (print-view window) nil)
  1548.  
  1549. (defmethod view-file-name ((view print-view))
  1550.   (slot-value view 'my-file-name))
  1551.  
  1552. (defmethod view-get ((view print-view) flag &optional option)
  1553.   (declare (ignore option))
  1554.   (if (equal flag :prec)
  1555.       (slot-value view 'my-print-record)
  1556.       (call-next-method)))
  1557.  
  1558. (defmethod view-put ((view print-view) flag value)
  1559.   (if (equal flag :prec)
  1560.     (setf (slot-value view 'my-print-record) value)
  1561.     (call-next-method)))
  1562.  
  1563. (setq *test-window* (make-instance 'print-window))
  1564. (setq *file-name* (choose-file-dialog))
  1565.  
  1566. ;; change the page setup attributes, they'll be saved with the file
  1567. (page-setup *test-window*)
  1568. (window-close *test-window*)
  1569.  
  1570. ;; create another window into the same "file"
  1571. ;; and see that the print-record has been restored.
  1572. (setq *test-window* (make-instance 'print-window))
  1573. (setf (slot-value *test-window* 'my-file-name) *file-name*)
  1574. (page-setup *test-window*)
  1575. |#
  1576.  
  1577. ;;; end of file